﻿using System;
using System.IO;
using System.Net;
using System.Linq;
using System.Text;
using System.Activities;
using System.Activities.Expressions;
using System.Activities.Presentation.PropertyEditing;
using System.Activities.Statements;
using System.Collections.Generic;
using System.ComponentModel;
using System.Xml;
using System.Xml.Xsl;
using System.Xml.XPath;
using System.Windows.Markup;

namespace Vision.Core.ActivityComponents.Xml
{
    /// <summary>
    /// 
    /// </summary>
    [ContentProperty("Body")]
    [System.ComponentModel.Designer(typeof(TransformDesigner))]
    public class Transform : NativeActivity
    {
        /// <summary>
        /// 
        /// </summary>
        public InArgument<Dictionary<string, object>> Parameters { get; set; }
        
        /// <summary>
        /// 
        /// </summary>
        public InArgument<byte[]> InputXmlFile { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public InArgument<byte[]> InputXsltFile { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public OutArgument<byte[]> OutputFile { get; set; }

        /// <summary>
        /// 
        /// </summary>
        [Browsable(false)]
        [DefaultValue(null)]
        public ActivityAction<byte[]> Body { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public Transform()
        {
            this.Body = new ActivityAction<byte[]>()
            {
                Argument = new DelegateInArgument<byte[]>()
                {
                    Name = "transformData"
                }
            };
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="metadata"></param>
        protected override void CacheMetadata(NativeActivityMetadata metadata)
        {
            RuntimeArgument paramsArgument = new RuntimeArgument("Parameters", typeof(Dictionary<string, object>), ArgumentDirection.In, false);
            metadata.Bind(this.Parameters, paramsArgument);
            metadata.AddArgument(paramsArgument);

            RuntimeArgument xmlFileArgument = new RuntimeArgument("InputXmlFile", typeof(byte[]), ArgumentDirection.In, true);
            metadata.Bind(this.InputXmlFile, xmlFileArgument);
            metadata.AddArgument(xmlFileArgument);

            RuntimeArgument xsltFileArgument = new RuntimeArgument("InputXsltFile", typeof(byte[]), ArgumentDirection.In, true);
            metadata.Bind(this.InputXsltFile, xsltFileArgument);
            metadata.AddArgument(xsltFileArgument);

            RuntimeArgument outputFileArgument = new RuntimeArgument("OutputFile", typeof(byte[]), ArgumentDirection.Out, false);
            metadata.Bind(this.OutputFile, outputFileArgument);
            metadata.AddArgument(outputFileArgument);

            metadata.AddDelegate(this.Body);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        protected override void Execute(NativeActivityContext context)
        {
            XmlDocument xmlDoc = new XmlDocument();
            XmlDocument xslDoc = new XmlDocument();
            
            //Load Xml Document:
            using (MemoryStream mStream = new MemoryStream(context.GetValue(this.InputXmlFile))){
                xmlDoc.Load(mStream);
            }

            //Load Xslt Document:
            using (MemoryStream mStream = new MemoryStream(context.GetValue(this.InputXsltFile))){
                xslDoc.Load(mStream);
            }

            //Do Transform:
            XsltArgumentList args = new XsltArgumentList();
            if (context.GetValue(this.Parameters) != null){
                foreach (string key in context.GetValue(this.Parameters).Keys){
                    args.AddParam(key, "", context.GetValue(this.Parameters)[key]);
                }
            }

            byte[] outputData = null;
            using (MemoryStream mStream = new MemoryStream()){                                
                using (XmlTextWriter writer = new XmlTextWriter(mStream, Encoding.Default)){
                    XslCompiledTransform transform = new XslCompiledTransform();
                    transform.Load(xslDoc, XsltSettings.TrustedXslt, null);
                    transform.Transform(xmlDoc, args, writer);
                }
                outputData = mStream.ToArray();
            }

            context.SetValue(this.OutputFile, outputData);
                        
            xmlDoc = null;
            xslDoc = null;

            // schedule the next action
            if (this.Body != null && this.Body.Handler != null){
                context.ScheduleAction(this.Body, outputData);
            }
        }
    }
}
